package com.turing.post.report.impl;

import java.io.UnsupportedEncodingException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Calendar;

import javax.ejb.EJB;
import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;

import com.turing.post.common.util.PCPSCommonDao;
import com.turing.post.report.util.MchTradErrLog;
import com.turing.post.report.util.MchTradErrLogBusiness;
import com.turing.post.report.util.MchTradErrLogDao;
import com.turing.post.util.PCPSUtil;
import com.turing.post.util.SHA1;

import com.turing.post.util.PCPSApplicationException;

@Stateless(mappedName = "report.impl.MchTradErrLogBusinessImpl")
@Remote
@Local
public class MchTradErrLogBusinessImpl implements MchTradErrLogBusiness {

	@EJB(mappedName = "common.impl.PCPSCommonDaoImpl")
	private PCPSCommonDao pcpsCommonDaoImpl;

	@EJB(mappedName = "report.impl.MchTradErrLogDaoImpl")
	private MchTradErrLogDao mchTradErrLogDaoImpl;

	private String getReqXmlString(byte[] breqxml) {
		String reqxml = null;
		try {
			reqxml = new String(breqxml, "GB18030");
		} catch (UnsupportedEncodingException e) {
			reqxml = null;
		}
		return reqxml;
	}

	/**
	 * 仅获取turing程序的堆栈
	 * 
	 * @param ex
	 * @return
	 */
	private String getTuringStack(Exception e) {
		StackTraceElement[] ste = e.getStackTrace();
		StringBuilder sb = new StringBuilder();
		if (e instanceof PCPSApplicationException) {
			PCPSApplicationException pae = (PCPSApplicationException) e;
			sb.append(pae.toString());
		}
		for (StackTraceElement s : ste) {
			// 类名若非turing公司的类则忽略
			if (!s.getClassName().startsWith("com.turing."))
				continue;
			sb.append(s.toString());
			sb.append("\n");
		}
		return sb.toString();
	}

	/**
	 * 查找并替换字符串中指定表达式的内容
	 * 
	 * @param src
	 * @param regEx
	 * @param rep
	 * @return
	 */
	private String replaceAll(String src, String regEx, String rep) {
		Pattern pat = Pattern.compile(regEx);
		Matcher matcher = pat.matcher(src);
		if (matcher.find())
			return matcher.replaceAll(rep);
		return src;
	}

	/**
	 * 替换xml中的回车换行等内容
	 * 
	 * @param xml
	 * @return
	 */
	private String trimAll(String xml) {
		return replaceAll(xml, "\\s*|\t|\r|\n", "");
	}

	private String getXmlContent(String node, String xml, int maxlength) {
		Pattern pat = Pattern.compile("<" + node + ">[\\x00-\\xff]*<");
		Matcher matcher = pat.matcher(trimAll(xml));
		if (matcher.find()) {
			String result = replaceAll(matcher.group(), "<" + node + ">", "")
					.trim();
			int pos = result.indexOf("<");
			if (pos > 0)
				result = result.substring(0, pos);
//			System.out.println(node + "++++++++++++" + result);
			if (result.length() > maxlength)
				return result.substring(0, maxlength);
			else
				return result;
		}
		return "";
	}

	private String replaceXmlContent(String node, String xml, String content) {
		Pattern pat = Pattern.compile("<\\s*" + getRegStr(node)
				+ "\\s*>[^\\x3c]*<");
		Matcher matcher = pat.matcher(xml);
		if (matcher.find())
			return matcher.replaceAll("<" + node + ">" + content + "<");
		return xml;
	}

	private String getRegStr(String str) {
		char[] chlist = str.toCharArray();
		StringBuilder sb = new StringBuilder();
		for (char ch : chlist) {
			sb.append("[");
			sb.append(String.valueOf(ch).toUpperCase());
			sb.append(String.valueOf(ch).toLowerCase());
			sb.append("]");
		}
		return sb.toString();
	}

	/**
	 * 过滤报文中的密码等信息
	 * 
	 * @param reqxml
	 * @return
	 */
	public String fixReqXmlSecurityContent(String reqxml) {
		// Passwd NewPwd
		reqxml = replaceXmlContent("Passwd", reqxml, "*");
		reqxml = replaceXmlContent("NewPwd", reqxml, "*");
		// reqxml = replaceXmlContent("MerchantNo", reqxml, "*");
		return reqxml;
	}

	public MchTradErrLog getMchTradErrLogContent(String reqxml) {
		MchTradErrLog mtel = new MchTradErrLog();
		// <\\s* .... \\s*>\\s*\\d*<
		mtel.setMerchantNo(getXmlContent(getRegStr("MerchantNo"), reqxml, 15));
		mtel.setMrchBrchNo(getXmlContent(getRegStr("BrchNo"), reqxml, 27));
		mtel.setTerminalNo(getXmlContent(getRegStr("PosNo"), reqxml, 8));
		mtel.setCardNo(getXmlContent(getRegStr("CardNo"), reqxml, 19));
		return mtel;
	}

	@TransactionAttribute(javax.ejb.TransactionAttributeType.REQUIRES_NEW)
	public void createMchTradErrLog(byte[] breqxml, Exception ex) {
		String reqxml = getReqXmlString(breqxml);
		if (PCPSUtil.isEmpty(reqxml))
			return;
		if (ex == null)
			return;
		MchTradErrLog mtel = getMchTradErrLogContent(reqxml);
		mtel.setTranTime(pcpsCommonDaoImpl.getDatabaseSysTime());
		mtel.setReqXml(fixReqXmlSecurityContent(reqxml));
		mtel.setExcepStack(getTuringStack(ex));
		byte[] bs = mtel.getTranTime().toString().getBytes();
		byte[] dig = new byte[bs.length + breqxml.length];
		System.arraycopy(bs, 0, dig, 0, bs.length);
		System.arraycopy(breqxml, 0, dig, bs.length, breqxml.length);
		String logid = new SHA1().getDigestOfString(dig);
		mtel.setLogId(logid);

		Calendar cal = java.util.Calendar.getInstance();
		cal.setTime(mtel.getTranTime());
		int ml = cal.get(Calendar.MINUTE) % 15;

		// 删除30天以前的记录,每15分钟删除一次
		if (ml == 0) {
			try {
				cal.add(Calendar.DAY_OF_MONTH, -30);
				mchTradErrLogDaoImpl.removeExpired(cal.getTime());
			} catch (Exception e) {
			}
		}

		// 插入记录
		try {
			mchTradErrLogDaoImpl.insert(mtel);
		} catch (PCPSApplicationException e) {
		}
	}

	public static void main(String[] args) throws Exception {
		MchTradErrLogBusinessImpl m = new MchTradErrLogBusinessImpl();
		String s = "<?xml version=\"1. " + "0\" encoding=\"gb18030\"?><TransR "
				+ "equest> <TranC " + "ode>9001</TranCo "
				+ "de> <MerchantNo>981080800016101</MerchantNo> "
				+ " <TranTime>20130 " + "511161923</TranT " + "ime> <PosNo>71 "
				+ "000002</PosNo> " + " <PosSettBatchNo " + ">000000</PosSett "
				+ "BatchNo> <PosS " + "eqNo>000274</Pos " + "SeqNo> <TranDa "
				+ "te>20130511</Tra " + "nDate> <ReqSeq " + "No>000000000187< "
				+ "/ReqSeqNo> <Re " + "qBody> <Card " + "No>9810801300015 "
				+ "275811</CardNo> " + " <Track2>9810 " + "801300015275811= "
				+ "0000291500000000 " + "0</Track2> < " + "Track3>981080130 "
				+ "0015275811=00002 " + "915000000000</Tr " + "ack3> </ReqBod "
				+ "y> <TranMac>49 " + "EA1943E510E0AC86 " + "104CCBF64C85F41E "
				+ "06222D</TranMac> " + "</TransRequest> ";
		m.getMchTradErrLogContent(s);
		System.out.println(m.fixReqXmlSecurityContent(s));
	}

}